<?php

namespace App\Services;

use App\Common\Libs\ArrayHelper;
use App\Common\Libs\Dispatch\Queue;
use App\Common\Libs\HttpClient;
use App\Consts\ExceptionCode;
use App\Consts\GlobalConst;
use App\Consts\GlobalCounterConst;
use App\Consts\GlobalDynamicConst;
use App\Consts\GlobalNoteConst;
use App\Consts\GlobalQueueConst;
use App\Jobs\Controller\NoteJob;
use App\Models\Cache\Cache;
use App\Models\Cache\CacheKey;
use App\Models\IndexNote;
use Illuminate\Support\Facades\DB;

/**
 * Class NoteDataService
 * @package App\Services
 */
class NoteDataService extends BaseService
{

    /**
     * @var \App\Repository\NoteRepository
     */
    private $_repository;

    /**
     * NoteDataService constructor.
     */
    public function __construct()
    {
        parent::__construct();
        $this->_repository = repository()->NoteRepository;
    }

    /**
     * @param $params
     * @return mixed
     */
    public function onChoiceList($searchParams)
    {
        $noteList = $this->NoteService->choiceList($searchParams);

        $provider = IndexNote::getInstance()
            ->where('is_public', GlobalNoteConst::IS_PUBLIC)
            ->where('is_deleted', GlobalConst::IS_NOT_DELETE)
            ->where('is_shield', GlobalNoteConst::IS_NOT_SHIELD)
            ->where('is_view', GlobalNoteConst::IS_VIEW)
            ->where('article_id', $searchParams['article_id']);

        $provider->orWhere(function ($query) use ($searchParams) {
            $query->where('is_deleted', GlobalConst::IS_NOT_DELETE)
                ->where('user_id', $searchParams['current_user_id'])
                ->where('is_shield', GlobalNoteConst::IS_NOT_SHIELD)
                ->where('is_view', GlobalNoteConst::IS_VIEW)
                ->where('article_id', $searchParams['article_id']);
        });
        $count = $provider->count('id');

        return ArrayHelper::merge($noteList, [
            'count' => $count
        ]);
    }

    /**
     * @param $params
     * @return mixed
     */
    public function onLineList($searchParams)
    {
        $noteList = $this->NoteService->lineNoteList($searchParams);

        return $this->listResult($noteList);
    }

    public function onArticleNoteList($searchParams)
    {
        $count = IndexNote::getInstance()
            ->where('user_id', $searchParams['current_user_id'])
            ->where('is_deleted', GlobalConst::IS_NOT_DELETE)
            ->where('article_id', $searchParams['article_id'])
            ->count('id');

        $noteList = $this->NoteService->articleNoteList($searchParams);

        return $this->listResult(ArrayHelper::merge($noteList, [
            'count' => $count,
        ]));
    }

    public function onSearchList($searchParams)
    {
        $noteList = $this->NoteService->searchNoteList($searchParams);

        return $this->listResult($noteList);
    }

    /**
     * @param $params
     * @return mixed
     */
    public function onAdd($params)
    {
        $userId = $params['user_id'] ?? 0;
        if (empty($params['article_id']) || empty($params['content'])) {
            return $this->throwError();
        }

        $params['content'] = ltrim($params['content']);
        $params['content'] = rtrim($params['content']);
        // 验证文章是否可用
        $article = $this->ArticleService->verifyArticleIsAvailableByArticleId($params['article_id']);
        if (!$article) {
            return $this->throwError(ExceptionCode::ILLEGAL_PARAMETER, lang('app.Article is disable'));
        }

        DB::beginTransaction();
        try {
            // 新增笔记
            $note = $this->NoteService->createNote(ArrayHelper::merge($params, [
                'user_id' => $userId,
                'type' => GlobalNoteConst::TYPE_ARTICLE_NOTE,
            ]));
            if (!$note) {
                return $this->throwError();
            }

            // 新增笔记内容
            $noteContent = $this->NoteService->createNoteContent(ArrayHelper::merge($params, [
                'note_id' => $note->note_id,
            ]));
            if (!$noteContent) {
                return $this->throwError();
            }

            // 同步更新缓存计数
            $this->NoteService->syncCounterFromCache($note);

            // 队列添加笔记日志
            $this->NoteService->saveNoteLogCounterByQueue($note, $article->author_id);

            // 公共开笔记则 队列新增动态信息
            if ($note->is_public == GlobalNoteConst::IS_PUBLIC) {
                $queueMessageBody = [
                    'user_id' => $note->user_id,
                    'type' => GlobalDynamicConst::DYNAMIC_TYPE_NOTE,
                    'target_id' => $note->note_id,
                    'target_type' => GlobalConst::TARGET_TYPE_NOTE,
                ];
                $this->DynamicService->addDynamicByTarget($queueMessageBody);
            }

            DB::commit();

            // 添加到推荐系统
            service()->RecommendSystemService->addTarget([
                'target_id' => $note->note_id,
                'target_type' => GlobalConst::NOTE_TYPE_MAP[$note->type],
                'user_id' => $note->user_id
            ]);

            return $this->getResult(ArrayHelper::merge($note->commonFormat(), [
                'is_choice' => GlobalNoteConst::IS_NOT_CHOICE,
                'is_deleted' => GlobalConst::IS_NOT_DELETE,
                'is_public' => $params['is_public'],
                'is_shield' => GlobalNoteConst::IS_NOT_SHIELD,
                'content' => $noteContent->content,
            ]));
        } catch (\Exception $e) {
            DB::rollBack();
            return $this->throwError(ExceptionCode::CODE_FAIL);
        }
    }

    /**
     * @param $params
     * @return mixed
     */
    public function onAddLine($params)
    {
        $userId = $params['user_id'] ?? 0;
        if (empty($params['article_id']) ||
            empty($params['content']) ||
            empty($params['selected']) ||
            !array_key_exists('start_index', $params) ||
            !array_key_exists('end_index', $params)
        ) {
            return $this->throwError(ExceptionCode::ILLEGAL_PARAMETER, '', '80010');
        }

        if (empty($params['start_index'] < $params['end_index']) ||
            empty($params['start_index']) ||
            empty($params['end_index'])
        ) {
            return $this->throwError(ExceptionCode::ILLEGAL_PARAMETER, '', '80011');
        }

        // 验证文章是否可用
        $article = $this->ArticleService->verifyArticleIsAvailableByArticleId($params['article_id']);
        if (!$article) {
            return $this->throwError(ExceptionCode::ILLEGAL_PARAMETER, lang('app.Article is disable'), '80012');
        }

        DB::beginTransaction();
        try {
            // 新增笔记
            $note = $this->NoteService->createNote(ArrayHelper::merge($params, [
                'user_id' => $userId,
                'type' => GlobalNoteConst::TYPE_LINE_NOTE,
            ]));
            if (!$note) {
                return $this->throwError(ExceptionCode::ILLEGAL_PARAMETER, '', '80013');
            }

            // 新增笔记内容[sys_note_content]
            $noteContent = $this->NoteService->createNoteContent(ArrayHelper::merge($params, [
                'note_id' => $note->note_id,
                'user_id' => $userId,
            ]));
            if (!$noteContent) {
                return $this->throwError(ExceptionCode::ILLEGAL_PARAMETER, '', '80014');
            }

            // 新增文章节选[sys_note_selected]
            $noteSelected = $this->NoteService->createNoteSelected(ArrayHelper::merge($params, [
                'note_id' => $note->note_id,
            ]));
            if (!$noteSelected) {
                return $this->throwError(ExceptionCode::ILLEGAL_PARAMETER, '', '80015');
            }

            // 新增划线笔记记录[sys_note_line]
            $noteLine = $this->NoteService->createNoteLine(ArrayHelper::merge($params, [
                'note_id' => $note->note_id,
            ]));
            if (!$noteLine) {
                return $this->throwError(ExceptionCode::ILLEGAL_PARAMETER, '', '80016');
            }

            // 同步更新缓存计数
            $this->NoteService->syncCounterFromCache($note);

            // 队列添加笔记日志
            $this->NoteService->saveNoteLogCounterByQueue($note, $note->user_id);

            // 公共开笔记则 队列新增动态信息
            if ($note->is_public == GlobalNoteConst::IS_PUBLIC) {
                $queueMessageBody = [
                    'user_id' => $note->user_id,
                    'type' => GlobalDynamicConst::DYNAMIC_TYPE_NOTE,
                    'target_id' => $note->note_id,
                    'target_type' => GlobalConst::TARGET_TYPE_NOTE,
                ];
                $this->DynamicService->addDynamicByTarget($queueMessageBody);
            }

            DB::commit();

            // 添加到推荐系统
            service()->RecommendSystemService->addTarget([
                'target_id' => $note->note_id,
                'target_type' => GlobalConst::NOTE_TYPE_MAP[$note->type],
                'user_id' => $note->user_id
            ]);

            return $this->getResult(ArrayHelper::merge($note->commonFormat(), [
                'is_choice' => GlobalNoteConst::IS_NOT_CHOICE,
                'is_deleted' => GlobalConst::IS_NOT_DELETE,
                'is_public' => $params['is_public'],
                'is_shield' => GlobalNoteConst::IS_NOT_SHIELD,
                'content' => $noteContent->content,
                'selected' => $noteSelected->selected,
                'start_index' => $noteLine->start_index,
                'end_index' => $noteLine->end_index
            ]));
        } catch (\Exception $e) {
            DB::rollBack();
            return $this->throwError('', ExceptionCode::CODE_FAIL, "[80017] - " . $e->getMessage());
        }
    }

    /**
     * @param $params
     * @return mixed
     */
    public function onDel($params)
    {
        $userId = $params['user_id'] ?? 0;
        if (empty($params['id'])) {
            return $this->throwError();
        }

        // 校验笔记是否已经被删除，是否属于当前用户
        $canDel = $this->NoteService->canDelNote($params['id'], $userId);
        if (!$canDel) {
            return $this->throwError(ExceptionCode::ILLEGAL_PARAMETER, lang('app.Note is disable'));
        }

        DB::beginTransaction();
        try {
            // 删除笔记
            $note = $this->NoteService->delNote($params['id']);
            if (!$note) {
                return $this->throwError();
            }

            // 同步更新缓存计数
            $this->NoteService->syncCounterFromCache($note, GlobalCounterConst::DECREASE);

            // 队列添加删除笔记日志
            $this->NoteService->saveNoteLogCounterByQueue($note, $note->article->author_id, true);

            // 队列删除动态
            $this->DynamicService->delDynamicByNote([
                'user_id' => $note->user_id,
                'target_id' => $note->note_id,
                'is_public' => $note->is_public,
            ]);

            // 队列删除点赞
            $this->LikeService->deletedNoteToDelLikeByQueue([
                'user_id' => $note->user_id,
                'target_id' => $note->note_id,
            ]);

            // 从推荐中移除
            service()->RecommendSystemService->remove([
                'target_id' => $note->note_id,
                'target_type' => GlobalConst::NOTE_TYPE_MAP[$note->type],
            ]);

            // 删除话题关联关系
            Queue::getInstance(NoteJob::class)
                ->push([
                    'target_id' => $note->note_id,
                ], GlobalQueueConst::NOTE_DEL_TOPIC_TARGET_RELATION);

            DB::commit();

            return $this->operatingResult();
        } catch (\Exception $e) {
            DB::rollBack();
            return $this->throwError(ExceptionCode::CODE_FAIL);
        }
    }

    /**
     * 修改笔记信息
     * 注意
     *  1. 【公开->私密】【私密->公开】，旧状态计数 - 1，新状态计数 + 1
     * @param $params
     * @return array|mixed
     */
    public function onEdit($params)
    {
        if (empty($params['id'])) {
            return $this->throwError();
        }

        // 校验笔记是否已经被删除，是否属于当前用户
        $oldNote = $this->NoteService->canDelNote($params['id'], $params['current_user_id']);
        if (!$oldNote) {
            return $this->throwError(ExceptionCode::ILLEGAL_PARAMETER, lang('app.Note is disable'));
        }
        DB::beginTransaction();
        try {
            // 同步更新旧笔记缓存计数
            $this->NoteService->syncCounterFromCache($oldNote, GlobalCounterConst::DECREASE);

            // 修改笔记信息
            $note = $this->NoteService->editNote([
                'id' => $params['id'],
                'is_public' => $params['is_public']
            ]);

            if (!$note) {
                return $this->throwError();
            }

            // 同步更新缓存计数
            $this->NoteService->syncCounterFromCache($note);

            // 队列添加笔记日志
            $this->NoteService->saveNoteLogCounterByQueue($note, $note->article->author_id);

            // 转为私密后队列修改动态和消息的影响
            if ($note->is_public == GlobalNoteConst::IS_NOT_PUBLIC) {
                $this->NoteService->ifSelfNotedelDynamicAndMessage($note);

                // 队列删除点赞
                $this->LikeService->deletedNoteToDelLikeByQueue([
                    'user_id' => $note->user_id,
                    'target_id' => $note->note_id,
                ]);

                // 从推荐中移除
                $url = service()->ConfigService->getConfigByKey('recommendRemoveUrl');
                HttpClient::getInstance()->get($url . "?target_id={$note->note_id}&target_type=" . GlobalConst::NOTE_TYPE_MAP[$note->type]);
            }

            DB::commit();

            return $this->operatingResult();
        } catch (\Exception $e) {
            DB::rollBack();
            return $this->throwError(ExceptionCode::CODE_FAIL);
        }
    }

    /**
     * @param $params
     * @return mixed
     */
    public function onGetDetail($params)
    {
        $noteId = $params['id'];
        if (!$noteId) {
            return $this->throwError();
        }

        $note = $this->NoteService->getNote($noteId);
        if (!$note) {
            return $this->throwError();
        }
        $note = $this->NoteService->getNoteMoreFields($note);
        $note['is_like'] = $this->LikeService->judgeUserIsLiked($params['user_id'], $noteId);
        $note['is_collect'] = $this->CollectService->judgeCollected($params['user_id'], $noteId);

        Cache::getInstance([
            'note_id' => $note['id']
        ])->incrFromArray(CacheKey::COUNTER_NOTE, GlobalCounterConst::COUNT_VIEW);

        // 新增浏览记录
        service()->BrowseHistoryService->createByQueue([
            'user_id' => $note['user_id'],
            'target_id' => $note['id'],
            'target_type' => GlobalConst::TARGET_TYPE_NOTE,
        ]);

        // 推送到推荐系统
        service()->RecommendSystemService->addView([
            'target_id' => $note['id'],
            'target_type' => GlobalConst::NOTE_TYPE_MAP[$note['type']],
            'user_id' => $params['current_user_id'],
        ]);

        return $this->getResult($note);
    }

    /**
     * @param $params
     * @return mixed
     */
    public function onSimilar($params)
    {
        $userId = $params['user_id'] ?? 0;
        $id = $params['note_id'];
        if (!$id) {
            return $this->throwError();
        }
        $note = $this->NoteService->getNote($id);
        if (!$note) {
            return $this->throwError();
        }

        $params['page_size'] = GlobalNoteConst::PAGE_SIZE;
        $params['ignore'] = $note->note_id;
        $params['tab'] = GlobalNoteConst::TAB_SIMILAR;
        $params['article_id'] = $note->article_id;
        $params['order_by_like'] = GlobalNoteConst::ORDER_BY_LIKE;
        $params['user_id'] = $userId;
        $params['current_user_id'] = $userId;

        $noteList = $this->NoteService->noteList($params);

        $noteList = ArrayHelper::multisort($noteList['list'], ['count.like'], SORT_DESC);

        return $this->listResult($noteList);
    }

}
